/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.persistence.criteria;

/**
 * interface to describe a property of a persistent object.
 * 
 * @param <TYPE>
 *          The type of the property
 * @param <INNERTYPE>
 *          the type of the elements of the property
 */
public class PropertyField<TYPE, INNERTYPE>
{
  /**
   * the name of the property.
   */
  private final transient String propertyName;

  /**
   * the class of the type represented by this {@link PropertyField}.
   */
  private final transient Class<TYPE> fieldClass;

  /**
   * the class of the elements of the type represented by this
   * {@link PropertyField}.
   */
  private final transient Class<INNERTYPE> elementsClass;



  /**
   * returns a new {@link PropertyField} that is the description of a property
   * of a field represented with another {@link PropertyField}.
   * 
   * @param <TYPE>
   *          the type of the sub property
   * @param <INNERTYPE>
   *          the type of the elements of the property
   * @param property
   *          the description of the root property
   * @param subProperty
   *          the sub property of the root property
   * @return a new {@link PropertyField} that is the description of a property
   *         of a field represented with another {@link PropertyField}
   * @deprecated Use instance method instead
   */
  @Deprecated
  public static <TYPE, INNERTYPE> PropertyField<TYPE, INNERTYPE> subProperty(PropertyField<?, ?> property, PropertyField<TYPE, INNERTYPE> subProperty)
  {
    return property.subProperty(subProperty);
  }



  /**
   * returns a new {@link PropertyField} that is the description of a property
   * of a field represented with this {@link PropertyField}.
   * 
   * @param <SUBTYPE>
   *          the type of the sub property
   * @param <SUBINNERTYPE>
   *          the type of the elements of the property
   * @param subProperty
   *          the sub property of the root property
   * @return a new {@link PropertyField} that is the description of a property
   *         of a field represented with this {@link PropertyField}
   */
  public <SUBTYPE, SUBINNERTYPE> PropertyField<SUBTYPE, SUBINNERTYPE> subProperty(PropertyField<SUBTYPE, SUBINNERTYPE> subProperty)
  {
    return new PropertyField<SUBTYPE, SUBINNERTYPE>(subProperty.getFieldClass(), subProperty.getElementsClass(), getPropertyName() + "." + subProperty.getPropertyName());
  }



  /**
   * factory method.
   * 
   * @param <TYPE>
   *          the type of the sub property
   * @param fieldClass
   *          the class of the type represented by this {@link PropertyField}
   * @param propertyName
   *          the name of the property
   * @return a new {@link SimplePropertyField}
   */
  public static <TYPE> SimplePropertyField<TYPE> create(Class<? super TYPE> fieldClass, String propertyName)
  {
    return new SimplePropertyField<TYPE>(fieldClass, propertyName);
  }



  /**
   * factory method.
   * 
   * @param <TYPE>
   *          the type of the sub property
   * @param <INNERTYPE>
   *          the type of the elements of the property
   * @param fieldClass
   *          the class of the type represented by this {@link PropertyField}
   * @param elementsClass
   *          the class of the elements of the type represented by this
   *          {@link PropertyField}
   * @param propertyName
   *          the name of the property
   * @return a new {@link PropertyField}
   */
  public static <TYPE, INNERTYPE> PropertyField<TYPE, INNERTYPE> create(Class<? super TYPE> fieldClass, Class<? super INNERTYPE> elementsClass, String propertyName)
  {
    return new PropertyField<TYPE, INNERTYPE>(fieldClass, elementsClass, propertyName);
  }



  /**
   * constructor.
   * 
   * @param fieldClass
   *          the class of the type represented by this {@link PropertyField}
   * @param elementsClass
   *          the class of the elements of the type represented by this
   *          {@link PropertyField}
   * @param propertyName
   *          the name of the property
   */
  @SuppressWarnings("unchecked")
  protected PropertyField(Class<? super TYPE> fieldClass, Class<? super INNERTYPE> elementsClass, String propertyName)
  {
    this.fieldClass = (Class<TYPE>) fieldClass;
    this.elementsClass = (Class<INNERTYPE>) elementsClass;
    this.propertyName = propertyName;
  }



  /**
   * getter for the propertyName property.
   * 
   * @return the propertyName
   */
  public String getPropertyName()
  {
    return propertyName;
  }



  /**
   * getter for the fieldClass property.
   * 
   * @return the fieldClass
   */
  public Class<TYPE> getFieldClass()
  {
    return fieldClass;
  }



  /**
   * getter for the elementsClass property.
   * 
   * @return the elementsClass
   */
  public Class<INNERTYPE> getElementsClass()
  {
    return elementsClass;
  }
}
